# 脚本编写

脚本接口允许你在自己的服务器上运行 JavaScript 代码并将更新发送到世界中。连接到世界的每个人都会看到你编写的脚本地块的相同视图。你可以在地块上的任何要素中编写脚本，并从该脚本访问其他要素。

一旦你拥有一个地块，你就可以开始使用脚本引擎。Cryptovoxels 中的脚本编写主要是客户端为主，即大多数脚本将由客户端运行而不是服务器。

脚本编写的层次结构如下：

- 世界
  - [地块对象](https://wiki.cryptovoxels.com/Scripting/Scripting#the-parcel)
  - [要素对象](https://wiki.cryptovoxels.com/Scripting/Scripting#feature-object)
  - [玩家对象](https://wiki.cryptovoxels.com/Scripting/Scripting#player-object)
  - [要素基本 GUI 对象](https://wiki.cryptovoxels.com/Scripting/basic-gui-api)
    - [GUI 控制对象](https://wiki.cryptovoxels.com/Scripting/Scripting#guicontrol-object)

脚本示例：[点击此处](https://wiki.cryptovoxels.com/Scripting/Examples)

> 更多最新文档请参阅 [blog.cryptovoxels.com](http://blog.cryptovoxels.com/scripting-bundle/)
{.is-warning}

## 地块

本部分包含所有地块共有的属性、函数和事件。

### 属性

**ID** - `parcel.id = 500` - 返回一个整数，表示地块的 ID。

**Owner** - `parcel.owner = "0x..."` - 返回一个字符串，表示地块的所有者。

**Contributors** - `parcel.contributors = []` - 返回一个数组，表示地块的贡献者列表。

**allowLoggedInOnly** - `parcel.allowLoggedInOnly = false` - 返回一个布尔值。当设置为 true 时，所有未登录的用户将被踢出。

**isPrivate** - `parcel.isPrivate = false` - 返回一个布尔值，表示地块是否为私有。当设置为 true 时，所有未被允许进入地块的玩家将被踢出。参考 [allow,disallow](https://wiki.cryptovoxels.com/Scripting/Scripting#allowwallet-parcelallow0x)。

**allowedWallets** - `parcel.allowedWallets = ["0x..."]` - 返回一个数组，表示如果地块是私有的，允许进入地块的钱包列表。无法设置此属性，可以使用 [allow,disallow](https://wiki.cryptovoxels.com/Scripting/Scripting#allowwallet-parcelallow0x)。

> 注意：使用 `isPrivate` 将地块设为私有仍然需要用户先进入地块，然后才会被踢出。在自由空间中，`isPrivate`、`allow` 和 `disallow` 是无效的。
{.is-info}

### 函数

#### getFeatures - `parcel.getFeatures()`
- 返回：一个 Feature 对象列表

```js
let features = parcel.getFeatures();
```

#### getFeatureById - `parcel.getFeatureById(id)` 
- 参数：**id** - 所需要素的 ID；一个 *字符串*
- 返回：一个 Feature 对象

```js
let door = parcel.getFeatureById('door');
console.log('door:', door);
```

#### getFeatureByUuid - `parcel.getFeatureByUuid(Uuid)` 
- 参数：**Uuid** - 所需要素的 UUID；一个 *字符串*
- 返回：一个 Feature 对象

```js
let feature = parcel.getFeatureById('3ed2bdd2-7570-485d-85b3-e5fd950bf3c6');
console.log('feature:', feature);
```

#### getFeaturesByType - `parcel.getFeaturesByType(type)` 
- 参数：**type** - 所需要素类型；一个 *字符串*
- 返回：一个 Feature 对象列表

```js
let allVoxModels = parcel.getFeaturesByType('vox-model');
```
有效的类型有：

- `'vox-model'`
- `'button'`
- `'image'`
- `'sign'`
- `'polytext'`
- `'audio'`
- `'nft-image'`
- `'megavox'`
- `'text-input'`
- `'slider-input'`
- `'video'`

#### createFeature - `parcel.createFeature(type)` 
- 参数：**type** - 所需要素类型；一个 *字符串*
- 返回：一个 Feature 对象

```js
let newFeature = parcel.createFeature('vox-model');
```

> 创建要素时，它的位置和缩放为 [0,0,0]。因此，请在创建后记得为其指定位置和缩放。要了解如何执行此操作，请向下滚动查看 [要素对象](https://wiki.cryptovoxels.com/Scripting/Scripting#feature-object) -> 属性。
{.is-warning}

#### removeFeature - `parcel.removeFeature(f)` 
- 参数：**f** - 要移除的要素；一个 *Feature* 对象
- 返回：一个事件

```js
let chair = parcel.getFeatureById('chairvox')
parcel.removeFeature(chair);
```


#### getPlayers - `parcel.getPlayers()` 
- 参数：无
- 返回：一个玩家对象列表。

#### getPlayersWithinParcel - `parcel.getPlayersWithinParcel()` 
- 参数：无
- 返回：一个玩家对象列表。仅包含在地块内的玩家

#### fetchSnapshots(callback?) - `parcel.fetchSnapshots(callback?)`
- 参数：（可选）一个回调函数，在获取快照后调用。回调函数必须有一个参数，这将是一个快照数组。
- 返回：无
- **注意**：这在自由空间中不起作用。

#### setSnapshot(snapshot_id) - `parcel.setSnapshot(snapshot_id)`
- 参数：一个表示所选快照的整数 ID。
- 返回：无
- **注意**：这在自由空间中不起作用。

示例： 
```js
function myCallback(snapshots){
  parcel.setSnapshot(snapshots[0

].id)
}

feature.on('click',e=>{
  parcel.fetchSnapshots(myCallback)
})
```
> **要记住的两件事：**
**一**，通过脚本将地块还原为快照时，它不会保存在服务器上（只有客户端能看到）。还要注意，您的脚本将会丢失，因为它会被覆盖。
**二**，如果在调用 `setSnapshot` 后编辑了地块，它将在服务器上保存快照。
{.is-warning}


#### allow(wallet) - `parcel.allow("0x..")`
将 `wallet` 添加到地块为私有时允许的钱包列表。
- 参数：钱包地址；
- 返回：无；

#### disallow(wallet) - `parcel.disallow("0x..")`
将 `wallet` 从地块为私有时允许的钱包列表中删除。
- 参数：钱包地址；
- 返回：无；

#### isWalletAllowedIfPrivate(wallet) - `parcel.isWalletAllowedIfPrivate("0x..")`
检查在地块为私有时是否允许 `wallet` 进入地块。
- 参数：钱包地址；
- 返回：无；

## 地块事件

**玩家进入** - `parcel.on('playerenter', (e)=> {})` 
- 返回：一个包含玩家信息的事件 `e`。
- 例如：`e.player.name -> 返回 "Fayelure"`
- 当玩家进入地块时触发

**玩家离开** - `parcel.on('playerleave', (e)=> {})` 
- 返回：一个包含玩家信息的事件 `e`。
- 例如：`e.player.wallet -> 返回 "0xdbw2fr8..."`
- 当玩家离开地块时触发

**玩家附近** - `parcel.on('playernearby', (e)=> {})` 
- 返回：一个包含玩家信息的事件 `e`。
- 例如：`e.player.name -> 返回 "Fayelure"`
- 当玩家进入围绕地块的街道时触发

**玩家远离** - `parcel.on('playeraway', (e)=> {})` 
- 返回：一个包含玩家信息的事件 `e`。
- 例如：`e.player.name -> 返回 "Fayelure"`
- 当玩家离开地块附近/街道时触发

## 玩家对象

通过 `parcel.getPlayers()` 或 `feature.on('click', e => console.log(e.player))` 可以获得。目前只是一个对象，但将来会成为一个类。

### 属性：

* `player.name` => 'captainbenis.eth'
* `player.wallet` => '0x2D891ED45C4C3EAB978513DF4B92a35Cf131d2e2'
* `player.uuid` => 玩家的此实例的 avatar uuid（玩家可能有多个标签页打开，拥有不同的 avatar）

> 有多种方法可以伪造 `player.wallet` 和 `player.name`，不要相信或向此地址发送资金。在将来，我们将加强托管的脚本服务器的安全性，并在更新这些文档时进行更新。{.is-warning}

### 函数：

#### teleportTo(coordinates) - `player.teleportTo(coordinates)`
- 参数：字符串，例如 `'N@43W,250N,1U'`
- 返回：无
- 对于地块外的玩家已禁用
[查看示例](https://wiki.cryptovoxels.com/Scripting/Examples/teleport-player)

#### hasWearable(tokenId,collectionId?) - `player.hasWearable(tokenId,collectionId)`
- 参数：一个整数 `tokenId`，代表可穿戴物品的标记 ID，以及 `collectionId`，代表该可穿戴物品所属的集合的 ID。
- 返回：true 或 false。

#### emote(emoji) - `player.emote('😋')`
- 参数：字符串；一个由 Cryptovoxels 支持的表情符号。
有关支持的表情符号列表，请参阅 [Emojis](https://wiki.cryptovoxels.com/en/Social#emojis)。
您还可以在脚本中找到此列表 `console.log(emojis)`。
- 返回：无
- 对于地块外的玩家已禁用
**注意：此函数的速率被限制为 500 毫秒**

#### animate(animation) - `player.animate('Dance')`
**此函数已

被弃用，因为它过于具有侵入性。它将不再起作用（2022 年 3 月）**
- 参数：字符串；一个动画的名称。
支持的动画列表如下：
```
Idle , Dance, Wave, Sitting, Spin, Savage, kick, Uprock, Floss, backflip
```
您还可以在脚本中找到此列表 `console.log(animations)`。
- 返回：无
- 对于地块外的玩家已禁用
**注意：此函数的速率被限制为 10 秒**

#### hasEthereumNFT(contract,tokenId,successCallback?,failCallback?) - `player.hasEthereumNFT('0x...',5,(hasNFT)=>.., (reason)=>..`
- 参数： 
**Contract：** 字符串；交易的合约。
**tokenId：** 字符串或数字；要检查所属权的代币 ID。
**successCallback：** 函数；成功时将调用此函数。给定的参数是一个布尔值，指示玩家是否拥有 NFT。例如 `(hasNFT)=>{console.log('player has NFT :',hasNFT})`
**failCallback：** 函数；调用此函数失败。给定的参数是 API 失败的原因的字符串。
- 返回：无

#### kick() - `player.kick()`
- 参数：无
- 返回：无
- 对于地块外的玩家已禁用

### 事件：

**move** - `player.on('move', (e)=> {...})` 
- 返回：一个事件 `e`。

**click** - `player.on('click', (e)=> {...})` 
- 返回：一个事件 `e`。

**chat** - `player.on('chat', (e)=> {...})` 
- 返回：一个包含聊天文本的事件 `e`。

## 特征对象
此部分包括所有特征共有的属性、函数和事件。
> 对于特定特征的属性和方法，请转到 [features](https://wiki.cryptovoxels.com/features) 中所需的特征，并向下滚动到脚本属性。{.is-info}

### 属性

#### ID - `feature.id` 
- 返回：整数；特征的 ID。
- 可以设置。例如：`feature.id = 'myvoxId' ` 

#### 类型 - `feature.type` 
- 返回：字符串；特征的类型。

类型包括：
- 'vox-model'
- 'button'
- 'image'
- 'sign'
- 'polytext'
- 'richtext'
- 'audio'
- 'video'
- 'youtube'
- 'nft-image'
- 'megavox'
- 'text-input'
- 'spawn-point'

#### 位置 - `feature.position` 
- 返回：矢量，格式为 [x（*double*），y（*double*），z（*double*）]。
- 可以设置。例如：`feature.position.set(1, 0.72, 2)`
	 或 `feature.position.y = 0.72` 
   或 `feature.set({position:[1,0.72,2]})` 
- 位置是地块空间（不是世界空间）中的位置。
- 位置单位为米
> 有关位置的示例，请参阅 [scripting examples](https://wiki.cryptovoxels.com/Scripting/Examples/Move-rotate-scale-Feature#h-1-positions)。{.is-info}

#### 缩放 - `feature.scale` 
- 返回：矢量，格式为 [x（*double*），y（*double*），z（*double*）]。
- 可以设置。例如：`feature.scale.set(0.75, 0.75, 0.75)`
	 或 `feature.scale.y = 0.75` 
   或 `feature.set({scale:[0.75,0.75,0.75]})` 
> 有关缩放的示例，请参阅 [scripting examples](https://wiki.cryptovoxels.com/Scripting/Examples/Move-rotate-scale-Feature#h-3-scaling)。{.is-info}

#### 旋转 - `feature.rotation` 
- 返回：矢量，格式为 [x（*double*），y（*double*），z（*double*）]。
- 这是一个代理矢量对象。在其上调用 `set`，例如 `feature.rotation.set(0, 0, 0)` 
	 或 `feature.rotation.y = 3.14`。 
   或 `feature.set({rotation:[0,3.14,0]})` 
   
> 有关旋转的示例，请参阅 [scripting examples](https://wiki.cryptovoxels.com/Scripting/Examples/Move-rotate-scale-Feature#h-2-rotations)。{.is-info}
   
   
> 虽然虚拟世界界面使用度数，但脚本引擎使用弧度。
3.14（*pi*）将使项目旋转 180 度。
{.is-warning}

**注意**：位置、缩放和旋转是 `Vector3` 对象，具有 ES6 代理，以侦听对 `x`、`y` 和 `z` 的更新。

- 调用 `feature.position.x = 1` 是有效的。
- 调用 `feature.position.copyFrom(new Vector3(1, 2, 3))` 是有效的。
- 调用 `feature.position.set(1, 2, 3)` 是有效的。
- 调用 `feature.position.addInPlace(new Vector3(4, 5, 6))` 是有效的。
- 等等。
- 调用 `feature.position = new Vector3()` *无效*。

#### 描述 - `feature.description`
- 返回：一个字典，包含可以在对象上 `set` 的所有属性。 
- 注意：不要更改返回的对象，假定其为只读。调用 `set` 来更新描述中的属性。

### 方法


#### 克隆() - `feature.clone()`
- 返回：克隆的特征

#### 删除() - `feature.remove()`
从地块中删除特征
- 返回：无

#### 设置(dict) - `feature.set({ url: 'http://', ... })`
设置特征的属性
- 参数：一个对象，包含一个键和一个值，例如 {url:'

http://example.com'}
- 返回：无

#### 获取() - `feature.get()`
返回特征的属性的副本，这些属性可以在其中设置新值。

## 特征事件
特征支持的事件在特征部分中有具体介绍。

> 更多最新文档请参阅 [https://wiki.cryptovoxels.com/Scripting/Examples](https://wiki.cryptovoxels.com/Scripting/Examples)
{.is-warning}

我希望这些信息能帮助到你开始使用 Cryptovoxels 的脚本编写。有关脚本编写的更多信息和示例，请访问官方文档链接和示例链接。如果你有其他问题，随时问我！祝你在 Cryptovoxels 中编写有趣的脚本！